/**********************************************************************************************/
/* FBL_DateTimeEncode.h																	  	  */
/*                                                                       					  */
/* Copyright Paradigma 1993-2006															  */
/* All Rights Reserved                                                   					  */
/**********************************************************************************************/

#ifndef _FBL_DateTimeEncode_h 
	#define _FBL_DateTimeEncode_h
#pragma once
	
#include <VShared/FBL/publ/Headers/FBL_pre_header.h>

/**********************************************************************************************/
FBL_Begin_Namespace

#include <VShared/FBL/publ/Headers/FBL.h>

#pragma mark -
#pragma mark === Date ===


/**********************************************************************************************/
#if FBL_BIG_ENDIAN

union DateEncoded
{
	long  encoded;		// long value, the more date, the more value.
						// Dates can be <0, this means before 0 year.
	struct decoded
	{
		signed   y	: 23;		// year		-2^22 to +2^22
		unsigned m	: 4;		// month, 	1 - 12
		unsigned d	: 5;		// day, 	1 - 31
	} decoded;
}; 

#else // For Windows and Mac (with Intel processor) we need have back order of bit fields:

union DateEncoded
{
	long  encoded;		// long value, the more date, the more value.
						// Dates can be <0, this means before 0 year.
	struct
	{
		unsigned d	: 5;		// day, 	1 - 31
		unsigned m	: 4;		// month, 	1 - 12
		signed   y	: 23;		// year		-2^22 to +2^22
	} decoded;
}; 

#endif


/**********************************************************************************************/ 
inline long EncodeDate( long inYear, ushort inMonth, ushort inDay )
{
	FBL_CHECK( inMonth <= 12 ); 
	FBL_CHECK( inDay <= 31 ); 

	DateEncoded date;
	
	date.decoded.y = inYear;
	date.decoded.m = inMonth;
	date.decoded.d = inDay;
	
	return date.encoded;
}

inline void DecodeDate( long inDate, long& outYear, ushort& outMonth, ushort& outDay )
{
	DateEncoded date;
	
	date.encoded = inDate;
	
	outYear 	= date.decoded.y;
	outMonth	= date.decoded.m;
	outDay		= date.decoded.d;	
}

#pragma mark -
#pragma mark === Time ===


/**********************************************************************************************/
#if FBL_BIG_ENDIAN

union TimeEncoded
{
	ulong  encoded;	// ulong value, the more time, the more value.
	
	struct
	{
		unsigned h	: 5;	// hours		0 - 23
		unsigned m	: 6;	// minutes, 	0 - 59
		unsigned s	: 6;	// seconds, 	0 - 59
		unsigned ms	: 15;	// mili seconds,0 - 999
	} decoded;
};

#else // FBL_BIG_ENDIAN

union TimeEncoded
{
	ulong  encoded;	// ulong value, the more time, the more value.
	
	struct
	{
		unsigned ms	: 15;	// mili seconds,0 - 999
		unsigned s	: 6;	// seconds, 	0 - 59
		unsigned m	: 6;	// minutes, 	0 - 59
		unsigned h	: 5;	// hours		0 - 23
	} decoded;
};

#endif // FBL_BIG_ENDIAN


/**********************************************************************************************/ 
#if FBL_BIG_ENDIAN

union DateTimeEncoded
{
	llong encoded;
	struct
	{
		DateEncoded date;
		TimeEncoded time;
	} decoded;
};

#else // FBL_BIG_ENDIAN

union DateTimeEncoded
{
	llong encoded;
	struct
	{
		TimeEncoded time;
		DateEncoded date;
	} decoded;
};

#endif // FBL_BIG_ENDIAN


/**********************************************************************************************/ 
inline ulong EncodeTime( 
	ushort inHour, 
	ushort inMinutes, 
	ushort inSeconds, 
	ushort inMilliSeconds )
{
	FBL_CHECK( inHour <= 24 ); 
	FBL_CHECK( inMinutes <= 59 ); 
	FBL_CHECK( inSeconds <= 59 ); 
	FBL_CHECK( inMilliSeconds <= 999 ); 

	TimeEncoded time;

	time.decoded.h = inHour;
	time.decoded.m = inMinutes;
	time.decoded.s = inSeconds;
	time.decoded.ms = inMilliSeconds;

	return time.encoded;
}

inline void DecodeTime( 
	ulong inTime, 
	ushort& outHour, 
	ushort& outMinutes, 
	ushort& outSeconds, 
	ushort& outMilliSeconds )
{
	TimeEncoded time;

	time.encoded = inTime;

	outHour 	= (ushort) time.decoded.h;
	outMinutes	= (ushort) time.decoded.m;
	outSeconds	= (ushort) time.decoded.s;
	outMilliSeconds	= (ushort) time.decoded.ms;
}



#pragma mark -
#pragma mark === DateTime ===


/**********************************************************************************************/
#if FBL_BIG_ENDIAN

inline void EncodeDateTime( llong* outDateTime, long inDate, ulong inTime )
{
	long* p = (long*) outDateTime;
	
	p[0] = (long) inDate;
	p[1] = (long) inTime;
}


inline void DecodeDateTime( llong* inDateTime, long* outDate, ulong* outTime )
{
	long* p = (long*) inDateTime;

	*outDate =  (long) p[0];
	*outTime = (ulong) p[1];
}


inline long DateTime_GetDate( llong* inDateTime )
{
	long* p = (long*) inDateTime;
	return p[0];
}


inline ulong DateTime_GetTime( llong* inDateTime )
{
	long* p = (long*) inDateTime;
	return (ulong) p[1];
}


inline void DateTime_SetDate( llong* ioDateTime, long inDate )
{
	long* p = (long*) ioDateTime;
	p[0] = inDate;
}


inline void DateTime_SetTime( llong* ioDateTime, ulong inTime )
{
	ulong* p = (ulong*) ioDateTime;
	p[1] = inTime;
}


/**********************************************************************************************/
#else // FBL_BIG_ENDIAN


inline void EncodeDateTime( llong* outDateTime, long inDate, ulong inTime )
{
	long* p = (long*) outDateTime;
	
	p[0] = (long) inTime;
	p[1] = (long) inDate;
}

inline void DecodeDateTime( llong* inDateTime, long* outDate, ulong* outTime )
{
	long* p = (long*) inDateTime;

	*outDate =  (long) p[1];
	*outTime = (ulong) p[0];
}

inline long DateTime_GetDate( llong* inDateTime )
{
	long* p = (long*) inDateTime;
	return p[1];
}

inline ulong DateTime_GetTime( llong* inDateTime )
{
	long* p = (long*) inDateTime;
	return (ulong) p[0];
}

inline void DateTime_SetDate( llong* ioDateTime, long inDate )
{
	long* p = (long*) ioDateTime;
	p[1] = inDate;
}

inline void DateTime_SetTime( llong* ioDateTime, ulong inTime )
{
	ulong* p = (ulong*) ioDateTime;
	p[0] = inTime;
}

#endif // FBL_BIG_ENDIAN


/**********************************************************************************************/
inline llong EncodeDateTime( 
	long	inYear,	
	ushort	inMonth,		
	ushort	inDay,

	ushort	inHour,	
	ushort	inMinutes,	
	ushort	inSeconds, 
	ushort	inMilliSeconds )
{
	FBL_CHECK( inMonth <= 12 ); 
	FBL_CHECK( inDay <= 31 ); 
	FBL_CHECK( inHour <= 24 ); 
	FBL_CHECK( inMinutes <= 59 ); 
	FBL_CHECK( inSeconds <= 59 ); 
	FBL_CHECK( inMilliSeconds <= 999 ); 


	DateTimeEncoded dt;
	
	dt.decoded.date.decoded.y = inYear;
	dt.decoded.date.decoded.m = inMonth;
	dt.decoded.date.decoded.d = inDay;

	dt.decoded.time.decoded.h = inHour;
	dt.decoded.time.decoded.m = inMinutes;
	dt.decoded.time.decoded.s = inSeconds;
	dt.decoded.time.decoded.ms = inMilliSeconds;

	return dt.encoded;
}


/**********************************************************************************************/
FBL_End_Namespace

#include <VShared/FBL/publ/Headers/FBL_post_header.h>

#endif // _FBL_DateTimeEncode_h


